package com.powerband.apiheartrate.ble.fbkBleController

import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.content.Context
import android.util.Log
import com.powerband.apiheartrate.base.FBKArmBandCmd
import com.powerband.apiheartrate.ble.fbkBleDevice.FBKBleUuids
import no.nordicsemi.android.ble.BleManager
import no.nordicsemi.android.ble.MtuRequest
import no.nordicsemi.android.ble.callback.InvalidRequestCallback
import no.nordicsemi.android.ble.data.Data
import no.nordicsemi.android.ble.exception.BluetoothDisabledException
import no.nordicsemi.android.ble.exception.ConnectionException
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException
import no.nordicsemi.android.ble.exception.RequestFailedException
import no.nordicsemi.android.ble.ktx.suspend
import no.nordicsemi.android.ble.observer.ConnectionObserver
import java.lang.Exception
import java.util.UUID


class FBKConnection(
    context: Context,
    private val device: BluetoothDevice,
    private val delegate: FBKConnectionCallback,
) : BleManager(context) {

    private var writeChar: BluetoothGattCharacteristic? = null
    private var otaChar: BluetoothGattCharacteristic? = null
    private var notifyChar: BluetoothGattCharacteristic? = null
    private var heartChar: BluetoothGattCharacteristic? = null
    private var readCharMap: MutableMap<FBKArmBandCmd, BluetoothGattCharacteristic?> =
        mutableMapOf()
    private var isConnectting: Boolean = false
    override fun log(priority: Int, message: String) {
        Log.println(priority, "RRR", message)
    }

    override fun getMinLogPriority(): Int {
        return Log.VERBOSE
    }

    suspend fun conectBlue(retry: Int = 0, delay: Int = 0, tOut: Long = 20000) {
        if (isConnectting) {
            delegate.connectError(410, "正在连接中")
            return
        }
        isConnectting = true
        try {
            connect(device).retry(retry, delay).invalid {
                delegate.connectError(408, "invalidRequest")
            }.fail { _, status ->
                delegate.connectError(409, "ble connect fail $status")
            }.useAutoConnect(false).suspend()
        } catch (e: RequestFailedException) {
            delegate.disConnected()
            delegate.connectError(e.status, e.message ?: "连接出错")
        } catch (e: BluetoothDisabledException) {
            delegate.disConnected()
            delegate.connectError(405, "蓝牙不可用")
        } catch (e: DeviceDisconnectedException) {
            delegate.connectError(407, e.message ?: "DeviceDisconnectedException")
        } catch (e: BluetoothDisabledException) {
            delegate.connectError(407, e.message ?: "BluetoothDisabledException")
        }  catch (e: ConnectionException) {
            delegate.disConnected()
            delegate.connectError(407, e.message ?: "ConnectionException连接出错")
        } catch (e: Exception) {
            delegate.disConnected()
            delegate.connectError(407, e.message ?: "ConnectionException连接出错")
        } finally {
            isConnectting = false
        }
    }

    override fun initialize() {
        super.initialize()
        setNotificationCallback(notifyChar).with { _, data -> delegate.receiveNotify(data.value) }
        enableNotifications(notifyChar).enqueue()
        setNotificationCallback(heartChar).with { _, data -> delegate.receiveHeartRate(data.value) }
        enableNotifications(heartChar).enqueue()

        val batteryChar = readCharMap[FBKArmBandCmd.Battery]
        batteryChar?.let {
            setNotificationCallback(it).with { _, data -> delegate.receiveBattery(data.value) }
            enableNotifications(it).enqueue()
        }
    }

    override fun onServicesInvalidated() {
        disableNotifications(notifyChar).enqueue()
        disableNotifications(heartChar).enqueue()
        writeChar = null
        notifyChar = null
        heartChar = null
        delegate.disConnected()
    }

    override fun isRequiredServiceSupported(gatt: BluetoothGatt): Boolean {
        // Return false if a required service has not been discovered.
        gatt.services.forEach { service ->
            when (service.uuid) {
                FBKBleUuids.UUID_SERVICE_DEVICE -> {
                    service.characteristics.forEach {
                        when (it.uuid) {
                            FBKBleUuids.UUID_NOTIFY_CHARACTERISTIC -> notifyChar = it
                            FBKBleUuids.UUID_WRITE_CHARACTERISTIC -> writeChar = it
                        }
                    }
                }
                FBKBleUuids.UUID_SERVICE_BATTERY -> readCharMap[FBKArmBandCmd.Battery] =
                    service.getCharacteristic(FBKBleUuids.UUID_BATTERY_CHARCTERICTIC)
                FBKBleUuids.UUID_SERVICE_GERNERAL -> {
                    service.characteristics.forEach {
                        when (it.uuid) {
                            FBKBleUuids.UUID_MANU_CHARACTERISTIC -> readCharMap[FBKArmBandCmd.Manufacture] =
                                it
                            FBKBleUuids.UUID_MODEL_CHARACTERISTIC -> readCharMap[FBKArmBandCmd.ModelNum] =
                                it
                            FBKBleUuids.UUID_HARD_CHARACTERISTIC -> readCharMap[FBKArmBandCmd.Hardware] =
                                it
                            FBKBleUuids.UUID_FIRM_CHARACTERISTIC -> readCharMap[FBKArmBandCmd.Firmware] =
                                it
                            FBKBleUuids.UUID_SOFT_CHARACTERISTIC -> readCharMap[FBKArmBandCmd.Software] =
                                it
                            FBKBleUuids.UUID_SYSID_CHARACTERISTIC -> readCharMap[FBKArmBandCmd.SystemId] =
                                it
                        }
                    }
                }
                FBKBleUuids.UUID_SERVICE_HEART -> heartChar =
                    service.getCharacteristic(FBKBleUuids.UUID_HEART_CHARCTERICTIC)
                FBKBleUuids.UUID_SERVICE_OTA -> otaChar =
                    service.getCharacteristic(FBKBleUuids.UUID_OTA_CHARCTERICTIC)
            }
        }
        return true
        // return writeChar != null && notifyChar != null
    }

    suspend fun sendCMD(data: ByteArray) {
        try {
            writeCharacteristic(
                writeChar,
                data,
                BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
            ).suspend()
        } catch (e: DeviceDisconnectedException) {
            delegate.connectError(e.hashCode(), "设备断开")
        } catch (e: RequestFailedException) {
            val msg = e.message ?: "发送指令出错"
            if (msg.contains("133")) {
                refreshDeviceCache().enqueue()
            }
            delegate.connectError(e.status, msg)
        } catch (e: Exception) {
            delegate.connectError(e.hashCode(), "写指令出错")
        }
    }
     fun requestMTU(mtu: Int) {
         try {
             requestMtu(mtu).enqueue()
         } catch (e: Exception) {
             delegate.connectError(e.hashCode(), "请求MTU失败")
         }

    }
    suspend fun readCMD(type: FBKArmBandCmd): Data? {
        return try {
            val char = readCharMap[type] ?: return null
            readCharacteristic(char).suspend()
        } catch (e: DeviceDisconnectedException) {
            delegate.connectError(e.hashCode(), "设备断开")
            null
        } catch (e: RequestFailedException) {
            null
        } catch (e: Exception) {
            null
        }
    }

    suspend fun sendOTAPacket(data: ByteArray) {
        try {
            writeCharacteristic(
                otaChar,
                data,
                BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
            ).then { delegate.otaDidWriteValue() }.suspend()
        } catch (e: DeviceDisconnectedException) {
            delegate.connectError(e.hashCode(), "设备断开")
        } catch (e: RequestFailedException) {
            delegate.connectError(e.status,e.message ?: "发送OTA指令出错")
        } catch (e: Exception) {
            delegate.connectError(e.hashCode(),e.message ?: "Exception:发送OTA指令出错")
        }
    }

    suspend fun otaReadPacket(): Data? {
        return try {
            readCharacteristic(otaChar).suspend()
        } catch (e: DeviceDisconnectedException) {
            delegate.connectError(e.hashCode(), "OTA中设备断开")
            null
        } catch (e: RequestFailedException) {
            null
        } catch (e: Exception) {
            delegate.connectError(e.hashCode(),e.message ?: "Exception:读取OTA指令出错")
            null
        }

    }

//    override fun requestMtu(mtu: Int): MtuRequest {
//       return MtuRequest.newMtuRequest(55)
//    }

    fun toggleNotifyWith(status: Boolean, type: FBKArmBandCmd) {
        try {
            if (status) {
                enableNotifications(if (type == FBKArmBandCmd.HeartRate) heartChar else notifyChar).enqueue()
            } else {
                disableNotifications(if (type == FBKArmBandCmd.HeartRate) heartChar else notifyChar).enqueue()
            }
        } catch (e: DeviceDisconnectedException) {
            delegate.connectError(e.hashCode(), "toggleNotifyWith-设备断开")
        }

    }
}